﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Windows.Forms;

namespace LuaVM.Controls
{
	public partial class ScrollLogBox : UserControl
	{
		/// <summary>
		/// 最大文本长度，超出则自动清空
		/// </summary>
		public int MaxLength { get; set; } = 32767;

		/// <summary>
		/// 获取和设置控件中的文本
		/// </summary>
		public override string Text
		{
			get
			{
				return GetText();
			}

			set
			{
				SetText(value);
			}
		}

		/// <summary>
		/// 选中的文本
		/// </summary>
		public string SelectedText => richTextBox1.SelectedText;

		/// <summary>
		/// 控件是否获得焦点
		/// </summary>
		public override bool Focused => richTextBox1.Focused;

		/// <summary>
		/// 获取和设置控件的背景色
		/// </summary>
		public override Color BackColor
		{
			get
			{
				return base.BackColor;
			}

			set
			{
				richTextBox1.BackColor = value;
				base.BackColor = value;
			}
		}

		/// <summary>
		/// 获取和设置控件的默认文本色
		/// </summary>
		public override Color ForeColor
		{
			get
			{
				return base.ForeColor;
			}

			set
			{
				richTextBox1.ForeColor = value;
				base.ForeColor = value;
			}
		}

		/// <summary>
		/// 获取和设置控件的字体
		/// </summary>
		public override Font Font
		{
			get
			{
				return base.Font;
			}

			set
			{
				richTextBox1.Font = value;
				base.Font = value;
			}
		}

		/// <summary>
		/// 构造函数
		/// </summary>
		public ScrollLogBox()
		{
			InitializeComponent();
			richTextBox1.Dock = DockStyle.Fill;
		}

		/// <summary>
		/// 滚动到文本框最底端
		/// </summary>
		public virtual void ScrollToBottom()
		{
			richTextBox1.Select(richTextBox1.Text.Length, 0);
			richTextBox1.ScrollToCaret();
		}

		/// <summary>
		/// 向控件内添加一行文字并指定颜色（线程安全）
		/// </summary>
		/// <param name="text">待添加的文字</param>
		/// <param name="type">日志种类</param>
		public virtual void Append(string text, LogTextType type = LogTextType.Normal)
		{
			if (richTextBox1.InvokeRequired)
			{
				richTextBox1.Invoke(new AppendDelegate(InvokeAppend), new object[] { text, type });
			}
			else
			{
				InvokeAppend(text, type);
			}
		}

		/// <summary>
		/// 清空控件中的文本
		/// </summary>
		public virtual void Clear()
		{
			if (richTextBox1.InvokeRequired)
			{
				richTextBox1.Invoke(new ClearDelegate(InvokeClear));
			}
			else
			{
				InvokeClear();
			}
		}

		/// <summary>
		/// 获取控件中的文本
		/// </summary>
		/// <returns>控件文字</returns>
		public string GetText()
		{
			if (richTextBox1.InvokeRequired)
			{
				return (string)richTextBox1.Invoke(new GetTextDelegate(InvokeGetText));
			}

			return InvokeGetText();
		}

		/// <summary>
		/// 设置控件中的文本
		/// </summary>
		/// <param name="text">控件文字</param>
		public virtual void SetText(string text)
		{
			if (richTextBox1.InvokeRequired)
			{
				richTextBox1.Invoke(new SetTextDelegate(InvokeSetText), new object[] { text });
			}
			else
			{
				InvokeSetText(text);
			}
		}

		/// <summary>
		/// 根据日志种类返回颜色
		/// </summary>
		/// <param name="type">日志种类</param>
		/// <returns>对应的颜色</returns>
		public Color GetLogTypeColor(LogTextType type)
		{
			Color color;
			switch (type)
			{
				case LogTextType.Error:
					color = Color.Red;
					break;

				case LogTextType.Highlight:
					color = Color.Blue;
					break;

				case LogTextType.Critical:
					color = Color.Purple;
					break;

				case LogTextType.Warning:
					color = Color.Orange;
					break;

				case LogTextType.Verbose:
					color = Color.Gray;
					break;

				default:
					color = ForeColor;
					break;
			}
			return color;
		}

		#region 跨线程操作及回调
		private delegate void AppendDelegate(string text, LogTextType type);
		private void InvokeAppend(string text, LogTextType type)
		{
			// 规范化文字
			string line = string.Format("{0}\n", text ?? "");

			int caret = richTextBox1.SelectionStart;

			// 如果添加后将会超出最大长度限制，则先清空文本框原内容
			int curLength = richTextBox1.Text.Length;
			int length = line.Length;
			if (length + curLength > MaxLength)
			{
				richTextBox1.Clear();
				caret = 0;
			}

			// 用户是否正在查看文本框中的内容，如果是则停止自动滚动
			bool reviewing = caret < curLength - 1;

			// 添加文字行
			richTextBox1.AppendText(line);

			// 更改文字行颜色
			if (type != LogTextType.Normal)
			{
				Color color = LogTextHelper.GetLogTypeColor(type);
				richTextBox1.Select(richTextBox1.Text.Length - length, length);
				richTextBox1.SelectionColor = color;
			}

			if (!Focused)
			{
				ScrollToBottom();
			}
		}

		private delegate void ClearDelegate();
		private void InvokeClear()
		{
			richTextBox1.Clear();
		}

		private delegate void SetTextDelegate(string text);
		private void InvokeSetText(string text)
		{
			richTextBox1.Text = text ?? "";
		}

		private delegate string GetTextDelegate();
		private string InvokeGetText()
		{
			return richTextBox1.Text;
		}
		#endregion

		// 菜单开启时更改菜单项禁用状态
		private void contextMenuStrip1_Opened(object sender, EventArgs e)
		{
			menuCopy.Enabled = richTextBox1.SelectedText != "";
			menuClear.Enabled = richTextBox1.Text != "";
		}

		private void menuCopy_Click(object sender, EventArgs e)
		{
			Clipboard.SetDataObject(richTextBox1.SelectedText, true);
		}

		private void menuClear_Click(object sender, EventArgs e)
		{
			richTextBox1.Text = "";
		}
	}
}
